package net.mof.manual.meta

import com.squareup.javapoet.CodeBlock
import com.squareup.javapoet.ParameterizedTypeName
import com.squareup.javapoet.TypeName
import net.mof.manual.MarkedClassInfo
import net.mof.manual.Utils.JSONObject_ClassName
import net.mof.manual.Utils.arrayListClassName
import net.mof.manual.Utils.hashMapClassName
import net.mof.manual.Utils.iteratorClassName
import net.mof.manual.Utils.jsonObject
import net.mof.manual.Utils.listClassName
import net.mof.manual.Utils.manualClassName
import net.mof.manual.Utils.mapClassName
import net.mof.manual.Utils.stringClassName
import net.mof.manual.Utils.upFirstChar
import java.util.*
import java.util.function.Consumer

/**
 *
 *  map类型
 *
 * Created by LiYueHui on 2020/2/2.
 */
class MapFieldMetaInfo : BaseFieldMetaInfo() {

    var baseFieldList: List<BaseFieldMetaInfo>? = null
    var parameterMap = ParameterizedTypeName.get(
            mapClassName, stringClassName, TypeName.OBJECT)
    var iterator = ParameterizedTypeName.get(
            iteratorClassName, stringClassName)

    override fun optField(): String = "JSONObject"

    override fun instanceTypeName(): TypeName = JSONObject_ClassName

    override fun jsonToTypeGet(builder: CodeBlock.Builder, markedClassInfo: MarkedClassInfo) {
        val it = "__iterator"
        val mapValue = "__map"

        val __list = "__list__"
        val listP: ParameterizedTypeName = ParameterizedTypeName.get(listClassName,
                stringClassName)
        val arrayListP: ParameterizedTypeName = ParameterizedTypeName.get(
                arrayListClassName, stringClassName)

        val keysIterator = "keysIterator"
        val next_string = "__next_String"

        builder.addStatement("\$T \$L = new \$T()", hashMapClassName, mapValue,
                hashMapClassName)
        builder.beginControlFlow("if (\$L != null && \$L.length() > 0)", value,
                value)
        builder.addStatement("\$T \$L = \$L.keys()", iterator, it, value)
        builder.beginControlFlow("while(\$L.hasNext())", it)
        builder.addStatement("\$T \$L = \$L.next()", stringClassName, "__k", it)
        builder.addStatement("\$L.put(\$L,\$T.wrap(\$L.get(\$L)))", mapValue, "__k",
                JSONObject_ClassName, value, "__k")
        builder.endControlFlow()
        builder.addStatement("\$L.set\$L(\$L)", markedClassInfo.getFileName()?.toLowerCase(), upFirstChar(filedName()), mapValue)
        builder.endControlFlow()

        if (baseFieldList?.isEmpty() != true) {
            val list: MutableList<String?> = ArrayList()
            baseFieldList?.forEach(Consumer { baseFieldMetaInfo: BaseFieldMetaInfo -> list.add(baseFieldMetaInfo.value) })
            list.remove(value)
            builder.beginControlFlow("else")
            builder.addStatement("\$T \$L = new \$T()", listP, __list, arrayListP)
            for (i in list.indices) {
                builder.addStatement("\$L.add(\$S)", __list, list[i])
            }
            builder.addStatement("\$T \$L = \$L.keys()", iterator, keysIterator,
                    jsonObject)
            builder.beginControlFlow("while(\$L.hasNext())", keysIterator)
            builder.addStatement("\$T \$L = \$L.next()", stringClassName,
                    next_string, keysIterator)
            builder.beginControlFlow("if(!\$L.contains(\$L))", __list,
                    next_string)
            builder.addStatement("\$L.put(\$L,\$T.wrap(\$L.opt(\$L)).toString())",
                    mapValue, next_string, JSONObject_ClassName, jsonObject,
                    next_string)
            builder.endControlFlow()
            builder.endControlFlow()
            builder.addStatement("\$L.set\$L(\$L)", markedClassInfo.getFileName()
                    ?.toLowerCase(), upFirstChar(filedName()), mapValue)
            builder.endControlFlow()
        }
    }

    override fun typeToJsonObjectPut(builder: CodeBlock.Builder?, param: String?) {
        val it = "__iterator__"
        val key = "__key"
        val inputString = "_inputString_"
        val valueMap = value + "_map"

        builder!!.addStatement("\$T \$L = \$L.get\$L()", parameterMap, valueMap,
                param, upFirstChar(filedName()))
        builder.beginControlFlow("if(\$L != null && \$L.size() > 0)", valueMap,
                valueMap)
        builder.addStatement("\$T \$L = \$L.keySet().iterator()", iterator, it,
                valueMap)

        builder.beginControlFlow("while(\$L.hasNext())", it)
        builder.addStatement("\$T \$L = \$L.next()", stringClassName, key, it)
        builder.addStatement("\$T \$L = \$L.get(\$L).toString()", stringClassName,
                inputString, valueMap, key)
        builder.addStatement("\$L.put(\$L,\$T.isJsonStr(\$L)? new \$T(\$L):\$L)",
                jsonObject, key, manualClassName, inputString,
                JSONObject_ClassName, inputString, inputString)
        builder.endControlFlow()
        builder.addStatement("\$L.put(\$S,new \$T(\$L))", jsonObject, value,
                JSONObject_ClassName, value + "_map")
        builder.endControlFlow()
    }
}